home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / stevie.arc / SCREEN.C < prev    next >
Text File  |  1990-01-10  |  14KB  |  559 lines

  1. /*
  2.  * Routines to manipulate the screen representations.
  3.  *
  4.  * Extensive modifications by:  Tony Andrews       onecom!wldrdg!tony
  5.  * Turbo C 1.5 port by: Denny Muscatelli 061988
  6.  */
  7.  
  8. #include "stevie.h"
  9.  
  10. /*
  11.  * The following variable is set (in filetonext) to the number of physical
  12.  * lines taken by the line the cursor is on. We use this to avoid extra
  13.  * calls to plines(). The optimized routines lfiletonext() and lnexttoscreen()
  14.  * make sure that the size of the cursor line hasn't changed. If so, lines
  15.  * below the cursor will move up or down and we need to call the routines
  16.  * filetonext() and nexttoscreen() to examine the entire screen.
  17.  */
  18. static    int    Cline_size;    /* size (in rows) of the cursor line */
  19. static    int    Cline_row;    /* starting row of the cursor line */
  20.  
  21. /*
  22.  * filetonext()
  23.  *
  24.  * Based on the current value of Topchar, transfer a screenfull of
  25.  * stuff from Filemem to Nextscreen, and update Botchar.
  26.  */
  27.  
  28. static void
  29. filetonext()
  30. {
  31.     register int row, col;
  32.     register char *screenp = Nextscreen;
  33.     LPTR memp;
  34.     LPTR save;            /* save pos. in case line won't fit */
  35.     register char *endscreen;
  36.     register char *nextrow;
  37.     char extra[16];
  38.     int nextra = 0;
  39.     register int c;
  40.     int n;
  41.     int done;
  42.     int srow;        /* starting row of the current line */
  43.  
  44.     save = memp = *Topchar;
  45.  
  46.     /* The number of rows shown is Rows-1. */
  47.     /* The last line is the status/command line. */
  48.     endscreen = &screenp[(Rows-1)*Columns];
  49.  
  50.     srow = done = row = col = 0;
  51.     while ( screenp < endscreen && !done) {
  52.  
  53.         /* Get the next character to put on the screen. */
  54.  
  55.         /* The 'extra' array contains the extra stuff that is */
  56.         /* inserted to represent special characters (tabs, and */
  57.         /* other non-printable stuff.  The order in the 'extra' */
  58.         /* array is reversed. */
  59.  
  60.         if ( nextra > 0 )
  61.             c = extra[--nextra];
  62.         else {
  63.             c = (unsigned)(0xff & gchar(&memp));
  64.             if (inc(&memp) == -1)
  65.                 done = 1;
  66.             /* when getting a character from the file, we */
  67.             /* may have to turn it into something else on */
  68.             /* the way to putting it into 'Nextscreen'. */
  69.             if ( c == TAB && !P(P_LS) ) {
  70.                 strcpy(extra,"        ");
  71.                 /* tab amount depends on current column */
  72.                 nextra = ((P(P_TS)-1) - col%P(P_TS));
  73.                 c = ' ';
  74.             }
  75.             else if ( c == NUL && P(P_LS) ) {
  76.                 extra[0] = NUL;
  77.                 nextra = 1;
  78.                 c = '$';
  79.             } else if ( (n = chars[c].ch_size) > 1 ) {
  80.                 char *p;
  81.                 nextra = 0;
  82.                 p = chars[c].ch_str;
  83.                 /* copy 'ch-str'ing into 'extra' in reverse */
  84.                 while ( n > 1 )
  85.                     extra[nextra++] = p[--n];
  86.                 c = p[0];
  87.             }
  88.         }
  89.  
  90.         if ( c == NUL ) {
  91.             srow = ++row;
  92.             /*
  93.              * Save this position in case the next line won't
  94.              * fit on the screen completely.
  95.              */
  96.             save = memp;
  97.             /* get pointer to start of next row */
  98.             nextrow = &Nextscreen[row*Columns];
  99.             /* blank out the rest of this row */
  100.             while ( screenp != nextrow )
  101.                 *screenp++ = ' ';
  102.             col = 0;
  103.             continue;
  104.         }
  105.         if ( col >= Columns ) {
  106.             row++;
  107.             col = 0;
  108.         }
  109.         /* store the character in Nextscreen */
  110.         *screenp++ = c;
  111.         col++;
  112.     }
  113.     /*
  114.      * If we didn't hit the end of the file, and we didn't finish
  115.      * the last line we were working on, then the line didn't fit.
  116.      */
  117.     if (!done && c != NUL) {
  118.         /*
  119.          * Clear the rest of the screen and mark the unused lines.
  120.          */
  121.         screenp = &Nextscreen[srow * Columns];
  122.         while (screenp < endscreen)
  123.             *screenp++ = ' ';
  124.         for (; srow < (Rows-1) ;srow++)
  125.             Nextscreen[srow * Columns] = '@';
  126.         *Botchar = save;
  127.         return;
  128.     }
  129.     /* make sure the rest of the screen is blank */
  130.     while ( screenp < endscreen )
  131.         *screenp++ = ' ';
  132.     /* put '~'s on rows that aren't part of the file. */
  133.     if ( col != 0 )
  134.         row++;
  135.     while ( row < Rows ) {
  136.         Nextscreen[row*Columns] = '~';
  137.         row++;
  138.     }
  139.     if (done)    /* we hit the end of the file */
  140.         *Botchar = *Fileend;
  141.     else
  142.         *Botchar = memp;
  143. }
  144.  
  145. /*
  146.  * nexttoscreen
  147.  *
  148.  * Transfer the contents of Nextscreen to the screen, using Realscreen
  149.  * to avoid unnecessary output.
  150.  */
  151. static void
  152. nexttoscreen()
  153. {
  154.     register char *np = Nextscreen;
  155.     register char *rp = Realscreen;
  156.     register char *endscreen;
  157.     register int row = 0, col = 0;
  158.     int gorow = -1, gocol = -1;
  159.  
  160.     endscreen = &np[(Rows-1)*Columns];
  161.  
  162.     outstr(T_CI);        /* disable cursor */
  163.  
  164.     for ( ; np < endscreen ; np++,rp++ ) {
  165.         /* If desired screen (contents of Nextscreen) does not */
  166.         /* match what's really there, put it there. */
  167.         if ( *np != *rp ) {
  168.             /* if we are positioned at the right place, */
  169.             /* we don't have to use windgoto(). */
  170.             if (gocol != col || gorow != row) {
  171.                 /*
  172.                  * If we're just off by one, don't send
  173.                  * an entire esc. seq. (this happens a lot!)
  174.                  */
  175.                 if (gorow == row && gocol+1 == col) {
  176.                     outchar(*(np-1));
  177.                     gocol++;
  178.                 } else
  179.                     windgoto(gorow=row,gocol=col);
  180.             }
  181.             outchar(*rp = *np);
  182.             gocol++;
  183.         }
  184.         if ( ++col >= Columns ) {
  185.             col = 0;
  186.             row++;
  187.         }
  188.     }
  189.     outstr(T_CV);        /* enable cursor again */
  190. }
  191.  
  192. /*
  193.  * lfiletonext() - like filetonext() but only for cursor line
  194.  *
  195.  * Returns true if the size of the cursor line (in rows) hasn't changed.
  196.  * This determines whether or not we need to call filetonext() to examine
  197.  * the entire screen for changes.
  198.  */
  199. static bool_t
  200. lfiletonext()
  201. {
  202.     register int row, col;
  203.     register char *screenp;
  204.     LPTR memp;
  205.     register char *nextrow;
  206.     char extra[16];
  207.     int nextra = 0;
  208.     register int c;
  209.     int n;
  210.     bool_t eof;
  211.  
  212.     screenp = Nextscreen + (Cline_row * Columns);
  213.  
  214.     memp = *Curschar;
  215.     memp.index = 0;
  216.  
  217.     eof = FALSE;
  218.     col = 0;
  219.     row = Cline_row;
  220.  
  221.     while (!eof) {
  222.  
  223.         /* Get the next character to put on the screen. */
  224.  
  225.         /* The 'extra' array contains the extra stuff that is */
  226.         /* inserted to represent special characters (tabs, and */
  227.         /* other non-printable stuff.  The order in the 'extra' */
  228.         /* array is reversed. */
  229.  
  230.         if ( nextra > 0 )
  231.             c = extra[--nextra];
  232.         else {
  233.             c = (unsigned)(0xff & gchar(&memp));
  234.             if (inc(&memp) == -1)
  235.                 eof = TRUE;
  236.             /* when getting a character from the file, we */
  237.             /* may have to turn it into something else on */
  238.             /* the way to putting it into 'Nextscreen'. */
  239.             if ( c == TAB && !P(P_LS) ) {
  240.                 strcpy(extra,"        ");
  241.                 /* tab amount depends on current column */
  242.                 nextra = ((P(P_TS)-1) - col%P(P_TS));
  243.                 c = ' ';
  244.             } else if ( c == NUL && P(P_LS) ) {
  245.                 extra[0] = NUL;
  246.                 nextra = 1;
  247.                 c = '$';
  248.             } else if ( c != NUL && (n=chars[c].ch_size) > 1 ) {
  249.                 char *p;
  250.                 nextra = 0;
  251.                 p = chars[c].ch_str;
  252.                 /* copy 'ch-str'ing into 'extra' in reverse */
  253.                 while ( n > 1 )
  254.                     extra[nextra++] = p[--n];
  255.                 c = p[0];
  256.             }
  257.         }
  258.  
  259.         if ( c == NUL ) {
  260.             row++;
  261.             /* get pointer to start of next row */
  262.             nextrow = &Nextscreen[row*Columns];
  263.             /* blank out the rest of this row */
  264.             while ( screenp != nextrow )
  265.                 *screenp++ = ' ';
  266.             col = 0;
  267.             break;
  268.         }
  269.  
  270.         if ( col >= Columns ) {
  271.             row++;
  272.             col = 0;
  273.         }
  274.         /* store the character in Nextscreen */
  275.         *screenp++ = c;
  276.         col++;
  277.     }
  278.     return ((row - Cline_row) == Cline_size);
  279. }
  280.  
  281. /*
  282.  * lnexttoscreen
  283.  *
  284.  * Like nexttoscreen() but only for the cursor line.
  285.  */
  286. static void
  287. lnexttoscreen()
  288. {
  289.     register char *np = Nextscreen + (Cline_row * Columns);
  290.     register char *rp = Realscreen + (Cline_row * Columns);
  291.     register char *endline;
  292.     register int row, col;
  293.     int gorow = -1, gocol = -1;
  294.  
  295.     endline = np + (Cline_size * Columns);
  296.  
  297.     row = Cline_row;
  298.     col = 0;
  299.  
  300.     outstr(T_CI);        /* disable cursor */
  301.  
  302.     for ( ; np < endline ; np++,rp++ ) {
  303.         /* If desired screen (contents of Nextscreen) does not */
  304.         /* match what's really there, put it there. */
  305.         if ( *np != *rp ) {
  306.             /* if we are positioned at the right place, */
  307.             /* we don't have to use windgoto(). */
  308.             if (gocol != col || gorow != row) {
  309.                 /*
  310.                  * If we're just off by one, don't send
  311.                  * an entire esc. seq. (this happens a lot!)
  312.                  */
  313.                 if (gorow == row && gocol+1 == col) {
  314.                     outchar(*(np-1));
  315.                     gocol++;
  316.                 } else
  317.                     windgoto(gorow=row,gocol=col);
  318.             }
  319.             outchar(*rp = *np);
  320.             gocol++;
  321.         }
  322.         if ( ++col >= Columns ) {
  323.             col = 0;
  324.             row++;
  325.         }
  326.     }
  327.     outstr(T_CV);        /* enable cursor again */
  328. }
  329.  
  330. /*
  331.  * updateline() - update the line the cursor is on
  332.  *
  333.  * Updateline() is called after changes that only affect the line that
  334.  * the cursor is on. This improves performance tremendously for normal
  335.  * insert mode operation. The only thing we have to watch for is when
  336.  * the cursor line grows or shrinks around a row boundary. This means
  337.  * we have to repaint other parts of the screen appropriately. If
  338.  * lfiletonext() returns FALSE, the size of the cursor line (in rows)
  339.  * has changed and we have to call updatescreen() to do a complete job.
  340.  */
  341. void
  342. updateline()
  343. {
  344.     if (!lfiletonext())
  345.         updatescreen();        /* bag it, do the whole screen */
  346.     else
  347.         lnexttoscreen();
  348. }
  349.  
  350. void
  351. updatescreen()
  352. {
  353.     filetonext();
  354.     nexttoscreen();
  355. }
  356.  
  357. void
  358. screenclear()
  359. {
  360.     register char    *rp, *np;
  361.     register char    *end;
  362.  
  363.     outstr(T_ED);        /* clear the display */
  364.  
  365.     rp  = Realscreen;
  366.     end = Realscreen + Rows * Columns;
  367.     np  = Nextscreen;
  368.  
  369.     /* blank out the stored screens */
  370.     while (rp != end)
  371.         *rp++ = *np++ = ' ';
  372. }
  373.  
  374. void
  375. cursupdate()
  376. {
  377.     LPTR *p;
  378.     int inc, c, nlines;
  379.     int i;
  380.     int didinc;
  381.  
  382.     if (bufempty()) {        /* special case - file is empty */
  383.         *Topchar  = *Filemem;
  384.         *Curschar = *Filemem;
  385.     } else if ( LINEOF(Curschar) < LINEOF(Topchar) ) {
  386.         nlines = cntllines(Curschar,Topchar);
  387.         /* if the cursor is above the top of */
  388.         /* the screen, put it at the top of the screen.. */
  389.         *Topchar = *Curschar;
  390.         Topchar->index = 0;
  391.         /* ... and, if we weren't very close to begin with, */
  392.         /* we scroll so that the line is close to the middle. */
  393.         if ( nlines > Rows/3 ) {
  394.             for (i=0, p = Topchar; i < Rows/3 ;i++, *Topchar = *p)
  395.                 if ((p = prevline(p)) == NULL)
  396.                     break;
  397.         } else
  398.             s_ins(0, nlines-1);
  399.         updatescreen();
  400.     }
  401.     else if (LINEOF(Curschar) >= LINEOF(Botchar)) {
  402.         nlines = cntllines(Botchar,Curschar);
  403.         /* If the cursor is off the bottom of the screen, */
  404.         /* put it at the top of the screen.. */
  405.         /* ... and back up */
  406.         if ( nlines > Rows/3 ) {
  407.             p = Curschar;
  408.             for (i=0; i < (2*Rows)/3 ;i++)
  409.                 if ((p = prevline(p)) == NULL)
  410.                     break;
  411.             *Topchar = *p;
  412.         } else {
  413.             scrollup(nlines);
  414.         }
  415.         updatescreen();
  416.     }
  417.  
  418.     Cursrow = Curscol = Cursvcol = 0;
  419.     for ( p=Topchar; p->linep != Curschar->linep ;p = nextline(p) )
  420.         Cursrow += plines(p);
  421.  
  422.     Cline_row = Cursrow;
  423.     Cline_size = plines(p);
  424.  
  425.     for (i=0; i <= Curschar->index ;i++) {
  426.         c = Curschar->linep->s[i];
  427.         /* A tab gets expanded, depending on the current column */
  428.         if ( c == TAB && !P(P_LS) )
  429.             inc = P(P_TS) - (Curscol % P(P_TS));
  430.         else
  431.             inc = chars[(unsigned)(c & 0xff)].ch_size;
  432.         Curscol += inc;
  433.         Cursvcol += inc;
  434.         if ( Curscol >= Columns ) {
  435.             Curscol -= Columns;
  436.             Cursrow++;
  437.             didinc = TRUE;
  438.         }
  439.         else
  440.             didinc = FALSE;
  441.     }
  442.     if (didinc)
  443.         Cursrow--;
  444.  
  445.     if (c == TAB && State == NORMAL && !P(P_LS)) {
  446.         Curscol--;
  447.         Cursvcol--;
  448.     } else {
  449.         Curscol -= inc;
  450.         Cursvcol -= inc;
  451.     }
  452.     if (Curscol < 0)
  453.         Curscol += Columns;
  454.  
  455.     if (set_want_col) {
  456.         Curswant = Cursvcol;
  457.         set_want_col = FALSE;
  458.     }
  459. }
  460.  
  461. /*
  462.  * The rest of the routines in this file perform screen manipulations.
  463.  * The given operation is performed physically on the screen. The
  464.  * corresponding change is also made to the internal screen image.
  465.  * In this way, the editor anticipates the effect of editing changes
  466.  * on the appearance of the screen. That way, when we call screenupdate
  467.  * a complete redraw isn't usually necessary. Another advantage is that
  468.  * we can keep adding code to anticipate screen changes, and in the
  469.  * meantime, everything still works.
  470.  */
  471.  
  472. /*
  473.  * s_ins(row, nlines) - insert 'nlines' lines at 'row'
  474.  */
  475. void
  476. s_ins(row, nlines)
  477. int    row;
  478. int    nlines;
  479. {
  480.     register char    *s, *d;        /* src & dest for block copy */
  481.     register char    *e;        /* end point for copy */
  482.     register int    i;
  483.  
  484.     if (T_IL[0] == NUL)        /* can't do it */
  485.         return;
  486.  
  487.     /*
  488.      * It "looks" better if we do all the inserts at once
  489.      */
  490.     outstr(T_SC);            /* save position */
  491.  
  492.     for (i=0; i < nlines ;i++) {
  493.         windgoto(row, 0);
  494.         outstr(T_IL);
  495.     }
  496.  
  497.     windgoto(Rows-1, 0);    /* delete any garbage that may have */
  498.     outstr(T_EL);        /* been shifted to the bottom line */
  499.     outstr(T_RC);        /* restore the cursor position */
  500.  
  501.     /*
  502.      * Now do a block move to update the internal screen image
  503.      */
  504.     d = Realscreen + (Columns * (Rows - 1)) - 1;
  505.     s = d - (Columns * nlines);
  506.     e = Realscreen + (Columns * row);
  507.  
  508.     while (s >= e)
  509.         *d-- = *s--;
  510.  
  511.     /*
  512.      * Clear the inserted lines
  513.      */
  514.     s = Realscreen + (row * Columns);
  515.     e = s + (nlines * Columns);
  516.     while (s < e)
  517.         *s++ = ' ';
  518. }
  519.  
  520. /*
  521.  * s_del(row, nlines) - delete 'nlines' lines at 'row'
  522.  */
  523. void
  524. s_del(row, nlines)
  525. int    row;
  526. int    nlines;
  527. {
  528.     register char    *s, *d, *e;
  529.     register int    i;
  530.  
  531.     if (T_DL[0] == NUL)            /* can't do it */
  532.         return;
  533.  
  534.     /* delete the lines */
  535.     outstr(T_SC);                /* save position */
  536.     for (i=0; i < nlines ;i++) {
  537.         windgoto(row, 0);
  538.         outstr(T_DL);            /* delete a line */
  539.         if (i == 0) {
  540.             windgoto(Rows-2, 0);    /* delete any garbage that */
  541.             outstr(T_EL);        /* was on the status line */
  542.         }
  543.     }
  544.     outstr(T_RC);                /* restore position */
  545.  
  546.     /*
  547.      * do a block move to update the internal image
  548.      */
  549.     d = Realscreen + (row * Columns);
  550.     s = d + (nlines * Columns);
  551.     e = Realscreen + ((Rows - 1) * Columns);
  552.  
  553.     while (s < e)
  554.         *d++ = *s++;
  555.  
  556.     while (d < e)        /* clear the lines at the bottom */
  557.         *d++ = ' ';
  558. }
  559.